import { compileDefinition, compileScript, Scope } from "./script-compiler.js";
import { Stage } from "./stage.js";

class Scene {
    constructor(project) {
        this.project = project;
        this.stage = null;
        this.functions = new Map();

        this.variables = {};

        this.varScope = new Scope();
        this.varScope.prefix = "env.globals.";
    }

    async loadXml(xml) {
        if (xml.nodeName !== "scene") throw new Error("Expected <scene> tag");

        var blocksNode, stageNode;

        for (let child of xml.children) {
            switch (child.nodeName) {
                case "stage": {
                    stageNode = child;
                    break;
                }

                case "blocks": {
                    blocksNode = child;
                    break;
                }

                case "variables": {
                    for (let varNode of child.children) {
                        let varName = varNode.attributes.name.nodeValue;
                        let safeVarName = this.varScope.addVariable(varName);

                        // remove prefix
                        safeVarName = safeVarName.slice(this.varScope.prefix.length);
                        
                        let val = varNode.firstElementChild;
                        if (val) {
                            console.log(varNode);
                            let compiled = compileScript(varNode.firstElementChild);

                            console.log(`set ${safeVarName} to ${compiled}`);
                            this.variables[safeVarName] = eval(compiled);
                        } else {
                            this.variables[safeVarName] = 0;
                        }
                    }

                    break;
                }
            }
        }
        
        this.stage = new Stage(this);
        this.stage.loadXml(stageNode);

        // compile blocks after initializing stage
        // that is because global variables are defined in the stage
        for (let blockNode of blocksNode.children) {
            console.group("block compilation");

            try {
                var def = compileDefinition(blockNode, this.stage.varScope);

                this.functions.set(def.opcode, {
                    paramTypes: def.paramTypes,
                    func: def.func
                });
            } catch(err) {
                console.error(err);
            }

            console.groupEnd();
        }
    }

    getFunction(fname) {
        return this.functions.get(fname);
    }
}

export { Scene }